import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.HashSet;
import java.util.LinkedList;
import javax.swing.*;


public class DrawGraph extends JPanel 
{
        private GraphPanel graphPanel1;
       
        
        Vertex<Integer, Node> vertexid1;
        Vertex<Integer, Node> vertexid2;
        Edge<Integer> edge1;

        private JButton addvertex;
        private JButton addedge;
        private JButton removeVertex;
        private JButton removeEdge;
        private JButton exportfile;
        private JButton undirected;
        private JButton directed;
    
        int x1,y1,x2,y2;
        int nodeCount, id1, id2, id3, no;
        
	private boolean mouseListenerIsActive = false, mouseListenerIsActive1 = false, undirected1;
	private boolean mouseListenerIsActive3 = false, mouseListenerIsActive2 = false, mouseListenerIsActive4;	
        	
	
        Graph<Integer> graph1 = new Graph<Integer>();
    
        public DrawGraph()
        {
                setLayout(null);
                addButtonsPanel();
                       
                graphPanel1 = new GraphPanel();
                graphPanel1.setLocation(0, 300);
                graphPanel1.setBounds(300, 0, 600, 600);
                graphPanel1.setBackground(Color.white);
                graphPanel1.setBorder(BorderFactory.createTitledBorder("Draw Graph"));
                graphPanel1.addMouseListener(new MouseHandler());
                add(graphPanel1);
               
        }
        private void addButtonsPanel()
        {
                JPanel pan = new JPanel(new GridLayout(8,1));
                pan.setLocation(0, 0);
                pan.setBounds(0, 0, 290, 400);
                
                undirected = new JButton("UNDIRECTED");
                undirected.addActionListener(new MouseHandler());
        	pan.add(undirected);
        	
        	directed = new JButton("DIRECTED");
        	directed.addActionListener(new MouseHandler());
        	pan.add(directed);
                        
                addvertex = new JButton("ADD VERTEX");
                addvertex.addActionListener(new MouseHandler());
                pan.add(addvertex);
     
                addedge = new JButton("ADD EDGE");
                addedge.addActionListener(new MouseHandler());
                pan.add(addedge);
        
                removeVertex = new JButton("REMOVE VERTEX");
                removeVertex.addActionListener(new MouseHandler());
                pan.add(removeVertex);
        
                removeEdge = new JButton("REMOVE EDGE");
                removeEdge.addActionListener(new MouseHandler());
                pan.add(removeEdge);
        
                exportfile = new JButton("EXPORT TO FILE");
                exportfile.addActionListener(new MouseHandler());
                pan.add(exportfile);
                
                add(pan);
        
          
        }
        private class MouseHandler extends MouseAdapter implements ActionListener
        {
        	public void actionPerformed(ActionEvent event) 
		{
	     		if (event.getActionCommand().equals("ADD VERTEX") ) 
			{	
				 addvertex.setEnabled(false);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(true);
				 directed.setEnabled(true);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = true;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = false;
 			}
 			else if (event.getActionCommand().equals("REMOVE VERTEX") ) 
			{
			    	addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(false);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(true);
				 directed.setEnabled(true);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = true;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = false;
 			}
 				
 		 	else if (event.getActionCommand().equals("ADD EDGE") ) 
			{
				addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(false);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(true);
				 directed.setEnabled(true);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = true;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = false;
 			}
 			else if (event.getActionCommand().equals("REMOVE EDGE") ) 
			{	
				 addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(false);
				 undirected.setEnabled(true);
				 directed.setEnabled(true);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = true;	
				 mouseListenerIsActive4 = false;
 			}
 			else if (event.getActionCommand().equals("UNDIRECTED") ) 
			{	
				 addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(false);
				 directed.setEnabled(true);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = false;

				 undirected1 = true;	
 			}
 			else if (event.getActionCommand().equals("DIRECTED") ) 
			{	
			    	addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(true);
				 directed.setEnabled(false);
				 exportfile.setEnabled(true);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = false;

				 undirected1 = false;	
 			}
 			
 			else if (event.getActionCommand().equals("EXPORT TO FILE") ) 
			{

			    	 addvertex.setEnabled(true);
                        	 removeVertex.setEnabled(true);
				 addedge.setEnabled(true);
				 removeEdge.setEnabled(true);
				 undirected.setEnabled(true);
				 directed.setEnabled(true);
				 exportfile.setEnabled(false);

				 mouseListenerIsActive = false;
                        	 mouseListenerIsActive3 = false;
				 mouseListenerIsActive1 = false;	
				 mouseListenerIsActive2 = false;	
				 mouseListenerIsActive4 = true;
				 
				JPanel message = new JPanel();
       				message.add(new JLabel("FILE:"));              
		                message.add(new JTextField(""));
                		message.setBackground(Color.GREEN);
                		String s = (String)JOptionPane.showInputDialog(graphPanel1,"Enter the file name below","FileName", 		   JOptionPane.PLAIN_MESSAGE,null, null,"Type file name with extention as txt");
                		
				 try{
				 	FileWriter fstream1 = new FileWriter(s);
  				 	BufferedWriter out = new BufferedWriter(fstream1);
  				 	if(undirected1 == true)
  				 	{
  				 		out.write("U");
  				 		out.newLine();
  				 	}
  				 	else if(undirected1 == false)
  				 	{
  				 		out.write("D");
  				 		out.newLine();
  				 	}
  					out.write(graph1.toFileFormat());	
					out.close();	
				 }
				 catch(Exception e)	
				 {
					e.printStackTrace();
				}
 			}
             }
                public void mouseClicked(MouseEvent event)
                {
                	if(mouseListenerIsActive||mouseListenerIsActive3)
                	{
                        	if(event.isMetaDown())
                        	{
                        	}
                        	else if(event.isAltDown())
                        	{
                        	}
                        	else
                        	{                        		
            	        		int xPos = event.getX();
                        		int yPos = event.getY();
                        	
                                	if(canAddNode(xPos,yPos))
                                	{
                                        	nodeCount++;
                                        	Node n = new Node(xPos,yPos);
                                                                   
                                        	vertexid1 = new Vertex<Integer, Node>(nodeCount,n);
                                        	if(mouseListenerIsActive)
                                        	{
                                        		
                                        		graph1.addVertex(vertexid1);
                                        		
                                        		
                                        	}
                                        	no = graph1.getNoOfVertices();	
                                        	
                                	}
                                	else if(mouseListenerIsActive3)
                                        {	
                                                id3     = getNodeId(xPos,yPos);
                                                vertexid1 = graph1.getVertexNode(id1);          
                                        	
                                        	graph1.removeVertex(vertexid1);
                                        }	
                                	graphPanel1.repaint();
                             
                        	}
                        	 
                        	
                        }
                }
               
                public void mousePressed(MouseEvent event)
                {
                        x1 = event.getX();
                        y1 = event.getY();
               
                        id1 = getNodeId(x1, y1); 
                        if(id1>=0) 
                        {
                    	        vertexid1 = graph1.getVertexNode(id1);
                    	        
                        }
                }
                public void mouseReleased(MouseEvent event)
                {
                if(mouseListenerIsActive1||mouseListenerIsActive2)
                  {      
                  	if(event.isMetaDown())
                        	{ 
                        	}
                        	else if(event.isAltDown())
                        	{
                        	}
                        	else
                        	{
                        	        x2 = event.getX();
                        	        y2 = event.getY();
                        	        id2 = getNodeId(x2, y2);
                        	        
                        	        if(id2>=0) 
                        	        {
                        	                vertexid2 = (Vertex)graph1.getVertexNode(id2);
                        	                 
                        	        }
                        	        if(id1>=0 && id2 >=0 && id1 != id2 )
                        	        {
                        	        	int k = (int)Math.sqrt((Math.pow((x2-x1),2)+Math.pow((y2-y1),2)));
                        	                Edge<Integer> edge1 = new Edge<Integer>(vertexid1, vertexid2,k);
                        	                Edge<Integer> edge2 = new Edge<Integer>(vertexid2, vertexid1,k);
                        	                if(mouseListenerIsActive1)
                        	                {
                        	                	graph1.addEdge(edge1);
                        	                	if(undirected1 == true)
                        	                	graph1.addEdge(edge2);
                        	                }
                        	                else if(mouseListenerIsActive2)
                        	                {
                        	                	graph1.removeEdge(edge1);
                        	                	if(undirected1 == true)
                        	                	graph1.removeEdge(edge2);
                        	                }	
                        	         }           
                        	        graphPanel1.repaint();
                        	}
                 	}
                }
        }
        private boolean canAddNode(int x1, int y2)
        {
                Iterator vIter = graph1.getVertexIterator();
		while(vIter.hasNext()) 
        	{
                        vertexid2 = (Vertex)vIter.next();
                        Node n = (Node)vertexid2.getVertextInfo();
                         
                        double x = n.getX();
                        double y= n.getY();
            
                        if(x1>=x && (x1<=x+20) && y1>=y && (y1<=y+20))
                                return false;
                	
                }
                return true;
        }
        private int getNodeId(int x1, int y1)
        {
                Iterator vIter = graph1.getVertexIterator();
		while(vIter.hasNext()) 
        	{
			vertexid2 = (Vertex)vIter.next();                        
                        Node n = (Node)vertexid2.getVertextInfo(); 
                        int n1 = vertexid2.getVertexId();
                              
                        int x = (int) n.getX();
                        int y = (int) n.getY();
            
            
                        if((x1<=x+20)&& (x1>=x) && (y1<=y+20)&&(y1>=y)) 
                            return n1;
                        
                }
                return -1; 
        }
    
        private class GraphPanel extends JPanel
        {
                public GraphPanel()
                {
                        setLayout(null);
                }
        
                public void paintComponent(Graphics g)
                {
                        super.paintComponent(g);
            		                       
                        Iterator vIter = graph1.getVertexIterator();
			while(vIter.hasNext()) 
        		{
				vertexid2 = (Vertex)vIter.next();
                        	
                                       	Node n = (Node)vertexid2.getVertextInfo();
                                
                                	int n1 = vertexid2.getVertexId();
                                
                                	int x = (int)n.getX();
                                	int y = (int)n.getY();
                   			
          				g.setColor(Color.black);
                                	g.fillOval(x, y, 10, 10);
                                	g.drawString(n1+"", x, y);
                                	
                                                              	
                         }
                        drawEdges(g);
                }
                public void drawEdges(Graphics g)
                {
                                Iterator vIter = graph1.getEdgeIterator();
		    		while(vIter.hasNext()) 
        	    		{
					Edge edge1 = (Edge)vIter.next();                         
                                        int x, y;                                                     	                
                	                        vertexid1 = edge1.getVertexOne();
                	                        vertexid2 = edge1.getVertexTwo();
                				int w = (int)edge1.getWeight();
                				
                	                        Node node1 = (Node)vertexid1.getVertextInfo();
                	                        Node node2 = (Node)vertexid2.getVertextInfo();
                	
                	                        int x1 = (int) node1.getX();
                	                        int y1 = (int) node1.getY();
                	
                	                        int x2 = (int) node2.getX();
	                                        int y2 = (int) node2.getY();
	                                        x = (x1+x2)/2;
	                                        y = (y1+y2)/2;
	                                        
	                                        
        	                                g.drawLine(x1+8, y1+8, x2+8, y2+8);
        	                                g.drawString(w+"", x, y);
        	                               
        	                                
                	                
                                }
                }
        }
 }
